package com.o2opuzi.lib.web;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.MethodParameter;
import org.springframework.ui.ModelMap;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.view.RedirectView;
import org.springframework.web.util.HtmlUtils;
import org.springframework.web.util.WebUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.util.IOUtils;
import com.o2opuzi.lib.util.DateUtils;
import com.o2opuzi.lib.util.RandomStringUtils;


public class WebHelperImpl implements WebHelper{
	
	private HttpServletRequest request;
	
	private HttpServletResponse response;
		
	private ServletContext servletContext;
	
	private ModelAndViewContainer mavContainer;
	
	private MethodParameter parameter;
	
	private static final Log log = LogFactory.getLog(WebHelperImpl.class);

	public WebHelperImpl(HttpServletRequest request, HttpServletResponse response,MethodParameter parameter,ModelAndViewContainer mavContainer) {
		this.request = request;
		this.response = response;
		this.servletContext = request.getServletContext();
		this.parameter = parameter;
		this.mavContainer = mavContainer;
	}

	@Override
	public WebHelper attribute(String name, Object value) {
		mavContainer.addAttribute(name, value);
		return this;
	}

	@Override
	public String realPath(String path) {
		try {
			return WebUtils.getRealPath(servletContext, path);
		} catch (FileNotFoundException e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

	@Override
	public String getParam(String name) {
		String param = HtmlUtils.htmlEscape(request.getParameter(name));
		return StringUtils.isEmpty(param) == true?null:param;
	}

	@Override
	public String[] params(String name) {
		List<String> list = new ArrayList<String>();
		String[] values = request.getParameterValues(name);
		if(values != null){
			for (String string : values) {
				list.add(HtmlUtils.htmlEscape(string));
			}
		}
		return list.toArray(new String[list.size()]);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> T sessionAttr(String name) {
		return (T) request.getSession().getAttribute(name);
	}

	@Override
	public HttpServletRequest getRequest() {
		return request;
	}

	@Override
	public HttpServletResponse getResponse() {
		return response;
	}

	@Override
	public ServletContext getServletContext() {
		return servletContext;
	}


	@Override
	public void addCookie(String name, String value) {
		addCookie(name, value, 1000*60*60*24*365*10);		
	}

	@Override
	public void addCookie(String name, String value, int expiry) {
		Cookie cookie = new Cookie(name, value);
		cookie.setMaxAge(expiry);
		cookie.setPath("/");
		addCookie(cookie);		
	}

	@Override
	public void addCookie(Cookie cookie) {
		response.addCookie(cookie);
	}

	@Override
	public WebHelper attributeAll(Map<String, Object> attrs) {
		mavContainer.addAllAttributes(attrs);
		return this;
	}

	@Override
	public WebHelper view(String view) {
		mavContainer.setViewName(view);
		return this;
	}

	@Override
	public WebHelper render(String view) {
		return view(view);
	}

	@Override
	public void sendRedirect(String location) {
		/*
		StringBuilder sb  = new StringBuilder();
		if(location.startsWith("http") || location.startsWith("https"))
			sb.append(getContextPath());
		sb.append(location.indexOf("?") == -1?location+"?":location+"&");
		ModelMap model = mavContainer.getModel();
		System.out.println(model);
		int size = 0;
		for (Entry<String, Object> en : model.entrySet()){
			if(size == 0)
				sb.append(en.getKey()+"="+en.getValue());
			else
				sb.append("&"+en.getKey()+"="+en.getValue());
			size++;
		}*/
		RedirectView view = new RedirectView(location);
		mavContainer.setView(view);
	}

	@Override
	public WebHelper redirectModel(ModelMap modelMap) {
		mavContainer.setRedirectModelScenario(true);
		mavContainer.setRedirectModel(modelMap);
		return this;
	}

	@Override
	public String getIpAddress() {
		String ip = request.getHeader("x-forwarded-for");
		if(StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip))
			ip = request.getHeader("Proxy-Client-IP");
		if(StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip))
			ip = request.getHeader("WL-Proxy-Client-IP");
		if(StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip))
			ip = request.getRemoteAddr();
		return ip;
	}

	@Override
	public String getRequestOS() {
		String userAgent = request.getHeader("User-Agent").toLowerCase();
		String[] syss = {"iphone","android","ipad","wp"};
		if(StringUtils.isEmpty(userAgent))
			return "other";
		for (int i = 0; i < syss.length; i++)
			if(userAgent.indexOf(syss[i]) != -1)
				return syss[i];
		return "other";
	}

	@Override
	public String path() {
		return request.getServletPath();
	}

	@Override
	public String redirect(String location) {
		return "redirect:"+location;
	}

	@Override
	public String contextPath() {
		return request.getContextPath();
	}

	@Override
	public String jsonp(Object data) {
		return jsonp(params("callback"));
	}

	@Override
	public String jsonp(String name, Object data) {
		return name+"("+data+")";
	}

	@Override
	public String getSessionId() {
		return WebUtils.getSessionId(request);
	}

	
	public WebHelper sessionAttr(String name, Object value) {
		WebUtils.setSessionAttribute(request, name, value);
		return this;
	}
	
	@Override
	public MethodParameter getParameter() {
		return parameter;
	}

	@Override
	public Cookie getCookie(String name) {
		return WebUtils.getCookie(request, name);
	}

	@Override
	public String getCookieValue(String name) {
		Cookie cookie = getCookie(name);
		if(cookie != null)
			return cookie.getValue();
		return null;
	}

	@Override
	public String encodeUrl(String url) {
		return response.encodeURL(url);
	}

	@Override
	public String decodeUrl(String url) {
		try {
			return URLDecoder.decode(url, "utf-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			log.error(e.getMessage(), e);
			return null;
		}
	}

	@Override
	public WebHelper removeSessionAttr(String name) {
		request.getSession().removeAttribute(name);
		return this;
	}

	@Override
	public String host() {
		return request.getScheme()+"://"+request.getServerName();
	}

	@Override
	public String hostAndPort() {
		return host()+request.getRemotePort();
	}

	@Override
	public String locationHost() {
		return request.getScheme()+"://"+request.getServerName();
	}

	@Override
	public void removeCookie(String name) {
		addCookie(name, "", 0);
	}

	@Override
	public String getParamToString(String name) {
		return getParam(name);
	}

	@Override
	public Integer getParamToInteger(String name) {
		return getParamToInteger(name, null);
	}

	@Override
	public Long getParamToLong(String name) {
		return getParamToLong(name, null);
	}

	@Override
	public Date getParamToDate(String name) {
		return DateUtils.parse(getParam(name));
	}

	@Override
	public Integer getParamToInteger(String name, Integer defaultValue) {
		try {
			if(StringUtils.isEmpty(getParam(name)))
				return defaultValue;
			return Integer.parseInt(getParam(name));
		} catch (NumberFormatException e) {
			//e.printStackTrace();
			return defaultValue;
		}
	}

	@Override
	public Long getParamToLong(String name, Long defaultValue) {
		try {
			if(StringUtils.isEmpty(getParam(name)))
				return defaultValue;
			return Long.parseLong(getParam(name));
		} catch (NumberFormatException e) {
			e.printStackTrace();
			return defaultValue;
		}
	}

	public WebHelperImpl(){
		
	}


	public void setResponse(HttpServletResponse response) {
		this.response = response;
	}

	public HttpSession getSession() {
		return request.getSession();
	}



	public void setServletContext(ServletContext servletContext) {
		this.servletContext = servletContext;
	}

	public ModelAndViewContainer getMavContainer() {
		return mavContainer;
	}

	public void setMavContainer(ModelAndViewContainer mavContainer) {
		this.mavContainer = mavContainer;
	}

	public void setParameter(MethodParameter parameter) {
		this.parameter = parameter;
	}

	@Override
	public MapParam getParamMap() {
		Map<String, String[]> map = request.getParameterMap();
		MapParam mapParam = new MapParam();
		for (Entry<String, String[]> en : map.entrySet())
			if(en.getValue().length > 1)
				mapParam.put(en.getKey(), en.getValue());
			else
				mapParam.put(en.getKey(), en.getValue()[0]);
		return mapParam;
	}

	@Override
	public String getClientType() {
		String ua = request.getHeader("User-Agent").toLowerCase();
		if(ua.indexOf("MicroMessenger".toLowerCase())!= -1)
			return "weixin";
		if(ua.indexOf("alipayclient") != -1)
			return "alipay";
		return "other";
	}

	@Override
	public Double getParamToDouble(String name) {
		return Double.parseDouble(getParam(name));
	}

	@Override
	public void forward(Map<String, Object> data, String view) throws ServletException, IOException {
		for (Entry<String, Object> en : data.entrySet()) {
			request.setAttribute(en.getKey(), en.getValue());
		}
		request.getRequestDispatcher(view).forward(request, response);
	}

	@Override
	public boolean isGet() {
		return request.getMethod().toUpperCase().equals("GET");
	}

	@Override
	public boolean isPost() {
		// TODO Auto-generated method stub
		return request.getMethod().toUpperCase().equals("POST");
	}

	@Override
	public boolean isAjaxRequest() {
		boolean isAjaxRequest = false;
		String contentType =  request.getHeader("Accept");
		if(contentType != null){
			isAjaxRequest = contentType.indexOf("application/json") != -1;
		}
		return isAjaxRequest;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Map<String, Object> getRequestBodyToMap() {
		Map<String, Object> data = (Map<String, Object>) request.getAttribute("bodyMapObject");
		try {
			if(data == null){
				String string = getRequestBody();
				data = JSON.parseObject(string, Map.class);
				this.request.setAttribute("bodyMapObject", data);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return data;
	}

	@Override
	public String getRequestBody() {
		// TODO Auto-generated method stub
		try {
			return StreamUtils.copyToString(request.getInputStream(),Charset.forName("utf-8"));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	
	public static void main(String[] args) {
		System.out.println(RandomStringUtils.randomLetter(32));
	}
}